using System;
using AntEater.ComponentModel.Validation;
using System.ComponentModel;
using System.Collections.ObjectModel;

namespace AntEater.ComponentModel.BuildElements
{
    /// <summary>
    /// Provides a base implementation for all build elements.
    /// </summary>
    [Serializable]
    [BuildElement("BaseBuildElement")]
    public abstract class BuildElementBase : IBuildElement
    {
        /// <summary>
        /// Occurs when a property has changed.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Initializes a new instance of the <see cref="T:BuildElementBase"/> class.
        /// </summary>
        /// <param name="context">The context.</param>
        protected BuildElementBase(BuildFileDefinition context) {

            if (context == null) { throw new ArgumentNullException("context"); }

            this._context = context;
        }

        private IBuildElement _parent;

        /// <summary>
        /// Gets the parent.
        /// </summary>
        /// <value>The parent.</value>
        [Browsable(false)]
        public IBuildElement Parent {
            get { return _parent; }
            set { _parent = value; }
        }

        /// <summary>
        /// Gets the root.
        /// </summary>
        /// <value>The root.</value>
        [Browsable(false)]
        public IRootBuildElement Root {
            get {
                IBuildElement currentElement = this;
                IRootBuildElement root = currentElement as IRootBuildElement;

                while (currentElement.Parent != null && root == null) {
                    currentElement = currentElement.Parent;
                    root = currentElement as IRootBuildElement;
                }
                return root;
            }
        }

        /// <summary>
        /// Gets a value indicating whether this build element is imported from an external buildfile.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this build element is imported; otherwise, <c>false</c>.
        /// </value>
        [Browsable(false)]
        public bool IsImported {
            get {
                if (this.Root != null) {
                    return this.Root.BuildFilePath != this.Context.BuildFilePath;
                }
                else {
                    return true;
                }
            }
        }

        private BuildFileDefinition _context;

        /// <summary>
        /// Gets the context.
        /// </summary>
        /// <value>The context.</value>
        [Browsable(false)]
        public BuildFileDefinition Context {
            get { return _context; }
        }

        /// <summary>
        /// Determines whether this instance is valid.
        /// </summary>
        /// <value></value>
        /// <returns>
        /// 	<c>true</c> if this instance is valid; otherwise, <c>false</c>.
        /// </returns>
        [Browsable(false)]
        public abstract bool IsValid {
            get;
        }

        /// <summary>
        /// Validates the specified recursive.
        /// </summary>
        /// <param name="recursive">if set to <c>true</c> [recursive].</param>
        /// <returns></returns>
        public abstract ReadOnlyCollection<ValidationResult> Validate(bool recursive);

        /// <summary>
        /// Returns a <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
        /// </summary>
        /// <returns>
        /// A <see cref="T:System.String"></see> that represents the current <see cref="T:System.Object"></see>.
        /// </returns>
        public override string ToString() {
            return Utilities.GetTypeAttributeFromObject<BuildElementAttribute>(this).Name;
        }

        /// <summary>
        /// Creates a new object that is a copy of the current instance.
        /// </summary>
        /// <returns>
        /// A new object that is a copy of this instance.
        /// </returns>
        public virtual object Clone() {
            BuildElementBase newElement = this.Context.CreateNewBuildElement(this.GetType()) as BuildElementBase;

            return newElement;
        }

        /// <summary>
        /// Called when [property changed].
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        protected void OnPropertyChanged(string propertyName) {
            if (this.PropertyChanged != null) {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}
